﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using Cabal.Kernel.DataSet;


namespace Cabal.Kernel.Output
{
    /// <summary>
    /// 表示一个CabalSoul任务
    /// </summary>
    public class Mission
    {
        public Mission(MissionOwner owner,MissionData data)
        {
            _owner = owner;
            _data = data;
        }

        MissionOwner _owner;
        MissionData _data;
        public Priority7 PriorityLevel; //任务优先级别

        /// <summary>
        /// 任务所有者与订阅者
        /// </summary>
        public MissionOwner Owner
        {
            get { return _owner; }
            set { _owner = value; }
        }
        /// <summary>
        /// 任务数据
        /// </summary>
        public MissionData Data
        {
            get { return _data; }
            set { _data = value; }
        }

        /* 
         *  对于订阅者:
         *    AddListener()
         *    CloseReference()
         *    GetResult()
         *  对于输出模块:
         *    DoWork() //包括设置状态
         *    NoticeListener() //通知订阅者 而不是执行代码
         *    GetReferenceCount() //引用计数
         *  
         *  --
         *    State{get;}
         */


    }

    /// <summary>
    /// 保存任务拥有者信息的类
    /// </summary>
    public class MissionOwner
    {
        public MissionOwner()
        {
            _ref = new List<MissionReference>();
            _refsaved = new List<MissionReference>();
            _mainThread = System.Threading.Thread.CurrentThread;
        }

        bool noticing = false;
        List<MissionReference> _ref;
        List<MissionReference> _refsaved;
        System.Threading.Thread _mainThread;
        public System.Threading.Thread MainThread
        {
            get { return _mainThread; }
            set { _mainThread = value; }
        }

        public void Add(MissionReference mr)
        {
            CheckNoticing(false);
            _ref.Add(mr); 
        }
        public void AddRange(IEnumerable<MissionReference> mrs)
        {
            CheckNoticing(false);
            _ref.AddRange(mrs);
        }
        public void Remove(MissionReference mr)
        {
            CheckNoticing(false);
            _ref.Remove(mr);
        }
        public void ResetReferenceFlag() //what's this..?
        {
            _refsaved.Clear();

            foreach (MissionReference i in _ref)
                if (i.SetFlag)
                    _refsaved.Add(i);

            noticing = false;
        }
        public void Clear()
        {
            CheckNoticing(false);
            _refsaved.Clear();
        }
        
        /// <summary>
        /// 开始执行通知指令(执行于发起线程)
        /// </summary>
        /// <param name="sender">发起者</param>
        /// <param name="e">任务参数</param>
        public void StartNotice(object sender,MissionEventArgs e)
        {
            CheckNoticing(false); // not noticing

            ResetReferenceFlag();

            noticing = true;

            Notice(sender,e);

            if (_refsaved.Count == 0)
                noticing = false;
        }
        private void Notice(object sender, MissionEventArgs e)
        {
            //List<MissionReference> mrs = new List<MissionReference>(_ref);
            foreach (MissionReference i in _ref)
                if (i.Reference != null)
                    if (i.Reference(sender, e) == true)
                        _ref.Remove(i);
        }

        //剩余引用
        public int ReferenceLeft()
        {
            CheckNoticing(true);
            return _refsaved.Count;
        }
        public int ReferenceCount()
        {
            return _ref.Count;
        }

        private void CheckNoticing(bool assertflag)
        {
            if (assertflag != noticing)
            {
                if (noticing)
                    throw new Exception("Noticing...Please wait");
                else
                    throw new Exception("Please set the noticing flag first!");
            }
        }

    }

    /// <summary>
    /// 任务信息的基类,所有任务信息都要继承自这个类
    /// </summary>
    public abstract class MissionData
    {
        public MissionData()
        {
            _FlagSet = new CabalLinq();
            this.SetState(MissionState.Unstarted);
        }

        /// <summary>
        /// "任务状态"标志常量
        /// </summary>
        public static string Flag_State = "RunningState";
        /// <summary>
        /// "任务目标"标志常量
        /// </summary>
        public static string Flag_Target = "Target";
        public static string Flag_SourceIP = "Source";
        public static string Flag_SourceIP_Self = "Self";

        public static string MType_HttpRequest = "HttpRequestMission";
        public static string MType_BaiduPost   = "HttpRequestMission:BaiduPost";


        protected CabalLinq _FlagSet;
        /// <summary>
        /// 标志集合
        /// </summary>
        public CabalLinq FlagSet
        {
            get { return _FlagSet; }
        }

        //Description
        public abstract string GetMissionType();
        public override string ToString()
        {
            return "Cabal.MissionData<" + GetMissionType() + ">";
        }

        //Work
        /// <summary>
        /// 获取任务状态
        /// </summary>
        public MissionState GetState()
        {
            string result = FlagSet.GetValue(Flag_State);
            int rid;
            if (result == null || int.TryParse(result,out rid)) throw new Exception("未知错误！RunningState标志错误");
            return (MissionState)rid;
        }
        /// <summary>
        /// 设置任务状态
        /// </summary>
        protected void SetState(MissionState state)
        {
            FlagSet.SetValue(Flag_State, ((int)state).ToString());
        }
        /// <summary>
        /// 获取任务执行结果
        /// </summary>
        public abstract object GetResult();
        /// <summary>
        /// 执行任务
        /// </summary>
        public abstract object DoWork();

        //Gc
        /// <summary>
        /// 获取一个值，代表任务是否需要回收
        /// </summary>
        /// <param name="time">回收时限,单位毫秒</param>
        /// <returns></returns>
        public abstract bool NeedCollect(int time);

        //FlagSet (标志集合)
        public bool SelectExp(string[] exps)
        {
            foreach (string i in exps)
                if (FlagSet.Select(i)==false) return false;
            return true;
        }
        public bool SelectPair(CLKeyValuePair[] pairs)
        {
            foreach (CLKeyValuePair i in pairs)
                if (FlagSet.Select(i.Key, i.Value) == false) return false;
            return true;
        }
        public bool SelectPair(params string[] pairs)
        {
            // e.g.  SelectPair("Address","teiba.baidu.com"
            //                  "State","Running"
            //                  "UseProxy","No");

            if (pairs.Length % 2 != 0) throw new Exception("参数必须成对");
            for (int i = 0; i + 1 < pairs.Length; i += 2)
            {
                if (FlagSet.Select(pairs[i], pairs[i + 1]) == false) return false;
            }
            return true;
        }
    }

    /// <summary>
    /// 任务状态的枚举
    /// </summary>
    public enum MissionState
    {
        Unstarted,
        Running,
        Waiting,
        Failed,
        Succeed,
    }

    /// <summary>
    /// 任务状态匹配失败的异常
    /// </summary>
    public class MissionStateException : Exception
    {
        public MissionStateException(MissionData mdata, string describe)
            : base("任务执行状态错误 " + describe)
        {
            data = mdata;
        }
        public MissionData data;
    }

}
